/*************************************************************************
    > File Name: track.cpp
    > Author: fanzhihui
    > Mail: 953106194@qq.com 
    > Created Time: 2019年06月28日 星期五 09时58分19秒
 ************************************************************************/
#include "track.h"
#include<iostream>
#include "face_detect_task.h"
#include "tracked_face_info.h"
#include "ping_redis_task.h"
#include "face_track_task.h"
#include "config.h"
#include "log/logger.h"

double Min(double a,double b)
{
	if(a > b) return b;
	return a;
}


string encode(IplImage* img)
{
	cv::Mat img_encode = cvarrToMat(img); 

	std::vector<int> vecCompression_params;
	vecCompression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
	vecCompression_params.push_back(90);

	std::vector<uchar> data_encode;
	imencode(".jpg", img_encode, data_encode,vecCompression_params);
	
	return ImageBase64::encode(data_encode.data(),data_encode.size());
}


IplImage* pickout_face(cv::Mat& frame, double center_x,double center_y,double width)
{
	CvRect rect;
	rect.x = center_x - width/2;
	rect.y = center_y - width/2;
	rect.width = width;
	rect.height = width;

	if( Min(rect.x,rect.y) > 20 ) {
		rect.x = rect.x - 20;
		rect.y = rect.y - 20;
		rect.width = rect.height = width + 20 * 2;
	}	
	IplImage src(frame);

	cvSetImageROI(&src, rect);
	IplImage* tmp = cvCreateImage(cvSize(src.roi->width, src.roi->height), src.depth, src.nChannels);
	cvCopy(&src, tmp, NULL);
	cvResetImageROI(&src);

	return tmp;
}


void FaceTrack::Run(bool& bQuit,std::map<uint32_t,TaskQueue>& map_task_queue)
{
	cv::VideoCapture cap;
	bool ret = cap.open(Config::video_url);
	//std::cout << "open" << Config::video_url << " ret:" << ret << std::endl;
	if( !ret ) {
		bQuit = true;
		LOG(LOG_INFO,"open %s failed",Config::video_url.c_str());
		return;
	}
	cv::Mat frame;	
	std::vector<TrackFaceInfo> *track_info = new std::vector<TrackFaceInfo>();
	uint32_t frame_no = 0;	
	uint32_t track_frame_per_sec = 	Config::frame_rate / Config::frame_per_sec;

	while (!bQuit) {
		//cap.grab();
		frame_no++;
		//frame = cap.grab();
		cap >> frame;
		if (!frame.empty() 
				&& frame_no % track_frame_per_sec == 0) {

			track_info->clear();
			/* 用来计算算法执行时间 */
			int64_t t = cv::getTickCount();
			int size = FaceApiHelper::getInstance()->track(track_info, frame, Config::max_face_num);
			/* 相减为算法执行的时间 */
			t = cv::getTickCount() - t;
			std::cout << "detection time =" << t * 1000 / cv::getTickFrequency() << " ms" << std::endl;


			std::vector<tracked_face_t> tracked_faces;
			for (int i = 0; i < size; i++)
			{
				tracked_face_t tracked_face;

				TrackFaceInfo info = track_info->at(i);
				// 人脸信息
				FaceInfo ibox = info.box;

				tracked_face.center_x = ibox.mCenter_x;
				tracked_face.center_y = ibox.mCenter_y;
				tracked_face.width = ibox.mWidth;
				tracked_face.height = ibox.mWidth;
				tracked_face.angle = ibox.mAngle;
				tracked_face.headPose = info.headPose;
				tracked_face.score = info.score;

				if ( info.score < Config::min_score )
				{
					std::cout << "score is to low" << std::endl;
					continue;
				}
				std::cout << "score:"<< info.score << std::endl;

				IplImage* pick_face = pickout_face(frame,ibox.mCenter_x,ibox.mCenter_y,ibox.mWidth);	
				tracked_face.base64 = encode(pick_face);

				cvReleaseImage(&pick_face);
				tracked_faces.push_back(tracked_face);
			}

			if(!tracked_faces.empty()) {

				IplImage src(frame);
				
				if(Config::mode == "track"){
					map_task_queue[0].Push(new FaceTrackTask(encode(&src),tracked_faces));
				} else if(Config::mode == "detect"){
					map_task_queue[0].Push(new FaceDetectTask(encode(&src),tracked_faces));
				} else {
					map_task_queue[0].Push(new FaceTrackTask(encode(&src),tracked_faces));
					map_task_queue[0].Push(new FaceDetectTask(encode(&src),tracked_faces));
				}
			
			}

		}
		
		if(frame.empty()) {	
			ret = cap.open(Config::video_url);
			std::cout << "re open" << Config::video_url << " ret:" << ret << std::endl;
			LOG(LOG_INFO,"reopen %s %s",Config::video_url.c_str(), ret ? "success":"failed");
		}
		cv::waitKey(1);
		//frame.release();			
		PingRedisTask* task = new PingRedisTask();
		map_task_queue[0].Push(task);

	}
	cap.release();
}


